ItIron2023
react
我們昨天看了在渲染陣列時用index作為key的一些隱憂,今天我們輕鬆一點,來看一個相對簡單的問題,但即便是這樣的問題也時常發生在許多學習者或工程師身上,我們馬上開始吧!
請觀察一下這個codesandbox。
export default function App() {
const [userId, setUserId] = useState("");
const [userData, setUserData] = useState(null);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then((res) => res.json())
.then((data) => setUserData(data));
}, []);
return (
<div>
<h1>Data fetch with useEffect not work as expected</h1>
<input
type="text"
placeholder="Enter User ID"
value={userId}
onChange={(e) => setUserId(e.target.value)}
/>
<button onClick={() => setUserId(userId)}>Fetch User</button>
{userData && <div>{`User Name: ${userData.name}`}</div>}
</div>
);
}
程式碼極為單純,我們期待一開始在沒有userData時不顯示下方的div元素,接著當使用者輸入想請求的userId在input欄位或點擊按鈕後抓取資料,最終更新畫面讓我們看到該使用者的名稱。
但實際的結果卻有兩個問題。
請試著解釋並修復這兩個問題。
這次的題目就比較有意思一點了,會動用到我們之前談過的幾個觀念,首先我們需要先了解為什麼下方的div在userData.name為undefined的情況下仍會被渲染出來,條件渲染應該是有值才會渲染啊! 所以我們先在setState的部分加個log看看,這麼一來一切就會很清楚了。
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then((res) => res.json())
.then((data) => {
console.log(data); // 加入log
setUserData(data);
});
}, []);
接著我們看一下console的部分,你會發現一個有趣的東西
原來是因為我們一開始請求的url因為userId初始值為空字串,整個請求url會變為https://jsonplaceholder.typicode.com/users/
,在這個api的預設情況下會回傳一個長度為10的陣列,因此在第一次渲染時userData其實就是一個長度為10的陣列,並不是原本的null值,滿足了條件渲染因此div會被渲染出來,而你試圖去存取一個陣列的name屬性自然就會得到undefined。
OK,先了解了一個問題,接著是為什麼輸入值或是點擊按鈕會無效?通常這種情況你可能會以為是onChange或是onClick hanlder出了什麼問題,但若你去檢查你會發現一切正常,setUserId確實有正確的更新userId的值造成re-render,但卻仍沒有取得正確的資料。
這麼一講你應該明白問題在哪裡了,useEffect
根本沒有在點擊後再次去請求資料,原因在於你的dependency array為空陣列,因此它就只會在第一次渲染時執行一次callback,後續就完全不理人直到整個組件再次被mount時才會再運作,若你的log還留著你會發現它再也沒有去fetch任何資料,造成你看到的結果。
理解原因之後要修復就很簡單了,我們要做到以下兩件事情
修正後的程式碼如下,一切就照我們所想的運作囉!
useEffect(() => {
if (!userId) return // 僅在有userId時執行callback
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then((res) => res.json())
.then((data) => {
setUserData(data);
});
}, [userId]); // 加入正確的值在dependency array中觸發重新呼叫callback
今天的例子雖然很簡單但卻也帶出了一個在使用useEffect時常常會出現的問題,我們前幾天的文章有提到useEffect大致上分成三個部分,dependency array在沒有被正確的使用時就會造成這類非預期的行為,之後你在遇到useEffect未能正確執行時可以先試著往這個方向思考看看,我們明天見囉!
本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!